﻿using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Xml.Linq;
using LINQPad.Extensibility.DataContext;
using LINQPad.OpenAccess.Helpers;
using LINQPad.OpenAccess.Settings;

namespace LINQPad.OpenAccess.Services
{
    /// <summary>
    ///   <see cref="IDataContextSettingsRepository" />.
    /// </summary>
    public class DataContextSettingsRepository : IDataContextSettingsRepository
    {
        #region Private

        #region - Vars

        [DebuggerBrowsable( DebuggerBrowsableState.Never )]
        private DataContractSerializer __driverSettingsSerializer;

        #endregion

        #endregion

        #region Protected

        #region - Functions

        /// <summary>
        /// Creates the driver settings serializer.
        /// </summary>
        /// <returns></returns>
        protected virtual DataContractSerializer CreateDriverSettingsSerializer( )
        {
            return new DataContractSerializer( typeof( DriverSettings ) );
        }

        #endregion

        #region - Properties

        /// <summary>
        /// Gets the driver settings serializer.
        /// </summary>
        /// <value>
        /// The driver settings serializer.
        /// </value>
        protected DataContractSerializer DriverSettingsSerializer
        {
            get
            {
                return this.__driverSettingsSerializer ?? ( this.__driverSettingsSerializer = this.CreateDriverSettingsSerializer( ) );
            }
        }

        #endregion

        #endregion

        #region Public

        #region - Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="DataContextSettingsRepository" /> class.
        /// </summary>
        public DataContextSettingsRepository( ) { }
        /// <summary>
        /// Initializes a new instance of the <see cref="DataContextSettingsRepository" /> class.
        /// </summary>
        /// <param name="driverSettingsSerializer">The driver settings serializer.</param>
        public DataContextSettingsRepository( DataContractSerializer driverSettingsSerializer )
        {
            Guard.ArgumentNotNull( driverSettingsSerializer, "driverSettingsSerializer" );
            this.__driverSettingsSerializer = driverSettingsSerializer;
        }


        #endregion

        #endregion

        #region IDataContextSettingsRepository Members

        /// <summary>
        /// Gets the default settings.
        /// </summary>
        /// <param name="connectionInfo">The connection info.</param>
        /// <returns>
        /// The default settings
        /// </returns>
        public DriverSettings GetDefaultSettings( IConnectionInfo connectionInfo )
        {
            Guard.ArgumentNotNull( connectionInfo, "connectionInfo" );

            return new DriverSettings( );
        }
        /// <summary>
        /// Gets the settings.
        /// </summary>
        /// <param name="connectionInfo">The connection info.</param>
        /// <returns>
        /// The driver settings or <c>null</c>.
        /// </returns>
        public DriverSettings GetSettings( IConnectionInfo connectionInfo )
        {
            Guard.ArgumentNotNull( connectionInfo, "connectionInfo" );

            var driverData = connectionInfo.DriverData;
            if ( driverData == null )
                return null;

            DriverSettings driverSettings;
            using ( var ms = new MemoryStream( Encoding.UTF8.GetBytes( driverData.ToString( ) ) ) )
                driverSettings = ( DriverSettings ) this.DriverSettingsSerializer.ReadObject( ms );

            return driverSettings;
        }
        /// <summary>
        /// Saves the settings.
        /// </summary>
        /// <param name="connectionInfo">The connection info.</param>
        /// <param name="settings">The settings.</param>
        public void SaveSettings( IConnectionInfo connectionInfo, DriverSettings settings )
        {
            Guard.ArgumentNotNull( connectionInfo, "connectionInfo" );

            XElement driverData = null;
            if ( settings != null )
            {
                string xmlDriverData;
                using ( var ms = new MemoryStream( ) )
                {
                    this.DriverSettingsSerializer.WriteObject( ms, settings );
                    ms.Position = 0;
                    using ( var rdr = new StreamReader( ms, Encoding.UTF8 ) )
                        xmlDriverData = rdr.ReadToEnd( );
                }

                driverData = XElement.Parse( xmlDriverData );
            }

            connectionInfo.DriverData = driverData;
        }

        #endregion

        #region IDataContextSettingsRepository Members


        #endregion
    }
}
